# plugs/infoitem.py
#
#

""" information items .. keyword/description pairs """

__copyright__ = 'this file is in the public domain'

from gozerbot.commands import cmnds
from gozerbot.examples import examples
from gozerbot.redispatcher import rebefore, reafter
from gozerbot.datadir import datadir
from gozerbot.persist import Persist
from gozerbot.generic import lockdec
from gozerbot.aliases import aliases
from gozerbot.plughelp import plughelp
import thread

plughelp.add('infoitem', 'also known as factoids .. info can be retrieved \
by keyword or searched')

infolock = thread.allocate_lock()

# create lock descriptor
locked = lockdec(infolock)

class Infoitems(Persist):

    """ information items """

    @locked
    def add(self, item, issue):
        """ add an item """
        item = item.lower()
        if self.data.has_key(item):
            self.data[item].append(issue)
        else:
            self.data[item] = [issue]
        self.save()

    @locked
    def addnosave(self, item, issue):
        """ add item but don't save """
        item = item.lower()
        if self.data.has_key(item):
            self.data[item].append(issue)
        else:
            self.data[item] = [issue]

    @locked
    def deltxt(self, item, txt):
        """ delete todo item with txt in it """
        got = 0
        if not self.data.has_key(item):
            return got
        for i in range(len(self.data[item])-1, -1, -1):
            if txt in self.data[item][i]:
                del self.data[item][i]
                got += 1
                break
        if got:
            self.save()
        return got

    @locked
    def delete(self, item, itemnr):
        """ delete item with nr from list """
        try:
            del self.data[item.lower()][int(itemnr)]
            self.save()
            return 1
        except IndexError:
            return 0
        except ValueError:
            return 0
        except KeyError:
            return 0

    def size(self):
        """ return number of items """
        return len(self.data)

info = Infoitems(datadir + '/infoitems')

if not info.data:
    info.data = {}

def handle_infosize(bot, ievent):
    """ info-size .. show number of information items """
    ievent.reply("we have %s infoitems" % info.size())

cmnds.add('info-size', handle_infosize, ['USER', 'WEB'])
examples.add('info-size', 'show number of infoitems', 'info-size')

def handle_addinfoitem(bot, ievent, groups):
    """ <keyword> = <description> .. add information item """
    try:
        (what, description) = groups
    except ValueError:
        ievent.reply('i need <item> <description>')
        return
    if len(description) < 3:
        ievent.reply('i need at least 3 chars for the description')
        return
    info.add(what, description)
    ievent.reply('%s added' % description)

rebefore.add(10, '^(.+?)\s+=\s+(.+)$', handle_addinfoitem, 'USER')
examples.add('=', 'add description to item', 'dunk = top')

def handle_question(bot, ievent, groups):
    """ <keyword>? .. ask for information item description """
    try:
        what = groups[0]
    except IndexError:
        ievent.reply('i need a argument')
        return
    what = what.strip().lower()
    try:
        infoitem = info.data[what]
    except KeyError:
        ievent.reply('no infoitems known for %s' % what)
        return
    result = ""
    for item in infoitem:
        try:
            result += "%s .. " % item
        except:
            pass
    if result:
        ievent.reply(result[:-4])
    else:
        ievent.reply('no %s found' % what)

reafter.add(10, '^(.+)\?$', handle_question, ['USER', 'WEB'])
reafter.add(10, '^\?(.+)$', handle_question, ['USER', 'WEB'])
examples.add('?', 'show infoitems of <what>', '1) test? 2) ?test')

def handle_forget(bot, ievent):
    """ forget <keyword> <txttomatch> .. remove information item where \
        description matches txt given """
    if len(ievent.args) > 1:
        what = ' '.join(ievent.args[:-1])
        txt = ievent.args[-1]
    else:
        ievent.missing('<item> <txttomatch> (min 3 chars)')
        return
    if len(txt) < 3:
        ievent.reply('i need txt with at least 3 characters')
        return
    what = what.strip().lower()
    try:
        nrtimes = info.deltxt(what, txt)
    except KeyError:
        ievent.reply('no records matching %s found' % what)
        return
    if nrtimes:
        ievent.reply('item deleted')
    else:
        ievent.reply('delete %s of %s failed' % (txt, what))

cmnds.add('info-forget', handle_forget, ['FORGET', 'OPER'])
examples.add('info-forget', 'forget <item> containing <txt>', 'info-forget \
dunk bla')
aliases.data['forget'] = 'info-forget'

def handle_searchdescr(bot, ievent):
    """ info-sd <txttosearchfor> .. search information items descriptions """
    if not ievent.rest:
        ievent.missing('<item>')
        return
    else:
        what = ievent.rest
    what = what.strip().lower()
    result = ""
    for item, value in info.data.iteritems():
        for item2 in value:
            if item2.find(what) != -1:
                result += "[%s] %s .. " % (item, item2)
    if result:
        ievent.reply(result[:-4])
    else:
        ievent.reply('none found')

cmnds.add('info-sd', handle_searchdescr, ['USER', 'WEB'])
examples.add('info-sd', 'info-sd <txt> ..  search description of \
infoitems', 'info-sd http')
aliases.data['sd'] = 'info-sd'
aliases.data['sl'] = 'info-sd'

def handle_searchinfo(bot, ievent):
    """ info-si <txt> .. search information keywords """
    if not ievent.rest:
        ievent.missing('<txt>')
        return
    else:
        what = ievent.rest
    what = what.strip().lower()
    result = ""
    for item in info.data.keys():
        if item.find(what) != -1:
            result += "%s .. " % item
    if result:
        ievent.reply(result[:-4])
    else:
        ievent.reply('none found')

cmnds.add('info-si', handle_searchinfo, ['USER', 'WEB'])
examples.add('info-si', 'info-si <txt> ..  search the infoitems keys', \
'info-si test')
aliases.data['si'] = 'info-si'
